{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Execute flow as a function\n",
    "\n",
    "**Requirements** - In order to benefit from this tutorial, you will need:\n",
    "- A python environment\n",
    "- Installed prompt flow SDK\n",
    "\n",
    "**Learning Objectives** - By the end of this tutorial, you should be able to:\n",
    "- Execute a flow as a function\n",
    "- Execute a flow function with in-memory connection object override\n",
    "- Execute a flow function with fields override\n",
    "- Execute a flow function with streaming output\n",
    "\n",
    "**Motivations** - This guide will walk you through the main scenarios of executing flow as a function. You will learn how to consume flow as a function in different scenarios for more pythonnic usage.\n",
    "\n",
    "\n",
    "**Note**: the flow context configs may affect each other in some cases. For example, using `connection` & `overrides` to override same node. \n",
    "The behavior is undefined for those scenarios. Pleas avoid such usage."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example1: Load flow as a function with inputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from promptflow.client import load_flow\n",
    "\n",
    "\n",
    "flow_path = \"../../flows/standard/web-classification\"\n",
    "sample_url = \"https://www.youtube.com/watch?v=o5ZQyXaAv1g\"\n",
    "\n",
    "f = load_flow(source=flow_path)\n",
    "result = f(url=sample_url)\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example2: Load flow as a function with in-memory connection override"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You will need to have a connection named \"new_ai_connection\" to run flow with new connection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": [
     "parameters"
    ]
   },
   "outputs": [],
   "source": [
    "# provide parameters to create connection\n",
    "\n",
    "conn_name = \"new_ai_connection\"\n",
    "api_key = \"<user-input>\"\n",
    "api_base = \"<user-input>\"\n",
    "api_version = \"<user-input>\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# create needed connection\n",
    "import promptflow\n",
    "from promptflow.entities import AzureOpenAIConnection, OpenAIConnection\n",
    "\n",
    "\n",
    "# Follow https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/create-resource?pivots=web-portal to create an Azure Open AI resource.\n",
    "connection = AzureOpenAIConnection(\n",
    "    name=conn_name,\n",
    "    api_key=api_key,\n",
    "    api_base=api_base,\n",
    "    api_type=\"azure\",\n",
    "    api_version=api_version,\n",
    ")\n",
    "\n",
    "# use this if you have an existing OpenAI account\n",
    "# connection = OpenAIConnection(\n",
    "#     name=conn_name,\n",
    "#     api_key=api_key,\n",
    "# )"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = load_flow(\n",
    "    source=flow_path,\n",
    ")\n",
    "# directly use connection created above\n",
    "f.context.connections = {\"classify_with_llm\": {\"connection\": connection}}\n",
    "\n",
    "result = f(url=sample_url)\n",
    "\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 3: Local flow as a function with flow inputs override"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from promptflow.entities import FlowContext\n",
    "\n",
    "f = load_flow(source=flow_path)\n",
    "f.context = FlowContext(\n",
    "    # node \"fetch_text_content_from_url\" will take inputs from the following command instead of from flow input\n",
    "    overrides={\"nodes.fetch_text_content_from_url.inputs.url\": sample_url},\n",
    ")\n",
    "# the url=\"unknown\" will not take effect\n",
    "result = f(url=\"unknown\")\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Example 4: Load flow as a function with streaming output"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "f = load_flow(source=\"../../flows/chat/chat-basic\")\n",
    "f.context.streaming = True\n",
    "result = f(\n",
    "    chat_history=[\n",
    "        {\n",
    "            \"inputs\": {\"chat_input\": \"Hi\"},\n",
    "            \"outputs\": {\"chat_output\": \"Hello! How can I assist you today?\"},\n",
    "        }\n",
    "    ],\n",
    "    question=\"How are you?\",\n",
    ")\n",
    "\n",
    "\n",
    "answer = \"\"\n",
    "# the result will be a generator, iterate it to get the result\n",
    "for r in result[\"answer\"]:\n",
    "    answer += r\n",
    "\n",
    "print(answer)"
   ]
  }
 ],
 "metadata": {
  "description": "This guide will walk you through the main scenarios of executing flow as a function.",
  "kernelspec": {
   "display_name": "github_v2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.17"
  },
  "resources": "examples/flows/standard/web-classification, examples/flows/chat/chat-basic"
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
